/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#define OMEN_SOURCE 1

#include "OmenPlugin.h"

#include <stdexcept>

using namespace std;

namespace Omen {

  // ----------------------------------------------------------------------- //

  Plugin::Plugin(const std::wstring &filename) :
    sharedLibraryHandle(0),
    referenceCount(0),
    getEngineVersionAddress(0),
    registerPluginAddress(0) 
{
    // Try to load the plugin as a shared library
    sharedLibraryHandle = SharedLibrary::Load(filename);

    // Locate the plugin's exported functions
    try {
      getEngineVersionAddress = SharedLibrary::GetFunctionPointer<GetEngineVersionFunction>(sharedLibraryHandle, "getEngineVersion");
      registerPluginAddress = SharedLibrary::GetFunctionPointer<RegisterPluginFunction>(sharedLibraryHandle, "registerPlugin");

      // Initialize a new shared library reference counter
      referenceCount = new size_t(1);
    }
    catch(std::exception &) {
      SharedLibrary::Unload(sharedLibraryHandle);
      throw std::runtime_error( std::string("Not a valid plugin ").append(filename.begin(), filename.end()));
    }
  }

  /// <summary>
  ///   Creates a copy of a plugin that has already been loaded.
  ///   Required to provide correct semantics for storing plugins in
  ///   an STL map container.
  /// </summary>
  /// <param name="other">Other plugin instance to copy</param>
  Plugin::Plugin(const Plugin &other) :
    sharedLibraryHandle(other.sharedLibraryHandle),
    referenceCount(other.referenceCount),
    getEngineVersionAddress(other.getEngineVersionAddress),
    registerPluginAddress(other.registerPluginAddress) 
{
    // Increase DLL reference counter
    if(referenceCount) 
    {
      ++(*referenceCount);
    }
}

  /// <summary>
  ///   Destroys the plugin, unloading its library when no more references
  ///   to it exist.
  /// </summary>
Plugin::~Plugin() 
{
    int remainingReferences = --*(referenceCount);
    if(remainingReferences == 0) 
    {
        delete referenceCount;
        SharedLibrary::Unload(sharedLibraryHandle);
    }
}

/// <summary>Register the plugin to a kernel</summary>
/// <param name="kernel">Kernel the plugin should register to</param>
void Plugin::registerPlugin( Omen::IKernel* kernel) 
{
      registerPluginAddress(kernel);
}

} // namespace Omen
